# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

from . import _

import gtk
import urllib

from threading import Thread, Lock, Condition

import artwriter
import etude.plugins as ep
import modules

LYRICS_PROP = 'lyrics'

STATUS_FOUND = 1
STATUS_NOT_FOUND = 2
STATUS_STARTING = 3

class Querier(ep.PluginExtra):
    
    _short_name = "Lyrics querier"
    _version = "0.0"
    _unique = "LyricsQuerier-0.0"
    _title = "Lyrics"
    _config = {'source_priority': 'leos'}
    _license = "LGPL"

    def __init__(self, control):
        ep.PluginExtra.__init__(self, control)
        self._interfaces = { 'fetch_lyrics': self.push_custom }
        self.client = control.client
        self.art_writer = artwriter.ArtWriter(self.client)

        source_priority = self.get_config('source_priority').split(',')
        self.source_prio = []
        self.modules = {}
        
        for module in modules.queriers:
            self.modules[module.shortName] = module
        for s in source_priority:
            if self.modules.has_key(s):
                self.source_prio.append(self.modules[s])
        for querier in self.modules.itervalues():
            if querier not in self.source_prio:
                self.source_prio.append(querier)

        #for fetching lyrics
        self.queue = []
        self.threads = []
        self.run = True
        self.lock = Lock()
        self.cond = Condition()
        
        self.start(LyricsFetcherThread, threads=1)
        self.bind(self.client, "e_playback_current_id", self.song_changed)

    def push_custom(self, data):
        """interface for querying custom lyrics"""
        if isinstance(data, tuple) and len(data) == 3:
            item = FetchItem(*data)
            self.queue_push(item)

    
    def song_changed(self, widget, id):
        """if the song changed, change the info too"""
        nfo = self.client.playback.current_info
        if nfo.has_key('lyrics') and len(nfo['lyrics']) != 0:
            return False
        try:
            if (nfo.has_key('artist') and nfo.has_key('title') and
                    len(nfo['artist']) != 0 and len(nfo['title']) != 0):
                item = FetchItem(id, nfo['artist'], nfo['title'])
                self.queue_push(item)
        except ValueError:
            pass
        return False
    
    def unload(self):
        ep.PluginExtra.unload(self)
        self.stop()
    
    def start(self, threadobj, threads=2):
        """start the lyrics fetcher threads"""
        for i in range(threads):
            t = threadobj(str(i), self)
            t.daemon = True
            t.start()
            self.threads.append(t)
    
    def should_run(self):
        """if the thread should run or not"""
        self.cond.acquire()
        ret = self.run
        self.cond.release()
        return ret
    
    def queue_push(self, item):
        """push a song into the queue"""
        if not isinstance(item, FetchItem):
            raise ValueError("queue_push() only want's CoverItems")
        self.cond.acquire()
        self.queue.append(item)
        self.cond.notify()
        self.cond.release()
    
    def queue_pop(self):
        """pop a query item from the queue"""
        i = None
        self.cond.acquire()
        while not i:
            if len(self.queue) > 0:
                i = self.queue.pop()
            else:
                self.cond.wait()
        self.cond.release()
        return i

    def do_item(self, item):
        """process the query item"""
        
        for q in self.source_prio:
            item.status(item, STATUS_STARTING, "lyrics")
            lyrics = ''
            try:
                lyrics = q.process(item)
            except Exception, e:
                print("%s" % (e.message))
            if len(lyrics)>0:
                break


        if len(lyrics) > 0:
            item.status(item, STATUS_FOUND, lyrics)
        else:
            item.status(item, STATUS_NOT_FOUND)

    def stop(self):
        self.run = False
        self.cond.acquire()
        self.cond.notifyAll()
        self.cond.release()


class FetchItem(object):

    def __init__(self, id, artist, song_title):
        object.__init__(self)
        self.id = id
        self.artist = artist
        self.song_title = song_title

class LyricsFetcherThread(Thread):

    def __init__(self, name, parent):
        Thread.__init__(self)
        self.name = name
        self.engine = parent

    def thread_function(self, status_func):
        self.status_func = status_func

        while self.engine.should_run():
            item = self.engine.queue_pop()
            if not item:
                break
            item.status = self.status_func #set thread function
            self.engine.do_item(item)
            item.status = None
    
    def run(self):
        self.thread_function(self.handle_results)

    def handle_results(self, item, status, arg = None):
        artist = item.artist
        songtitle = item.song_title
        id = item.id

        if status == STATUS_FOUND:
            if arg:
                self.engine.art_writer.write(id, arg)
                print("Lyrics found")

        if status == STATUS_NOT_FOUND:
            print("Lyrics not found")

        if status == STATUS_STARTING:
            print("Lyrics fetch starting")

